#include "utils.h"

#include "CLayer.h"
#include "CNeuron.h"

/*----------------------------------------------------------------------------*/


CLayer::CLayer( int _inputsNum, int _neuronsNum, bool _isLast )
	:	m_inputsNum( _inputsNum )	
{
	m_resultValues.resize( _neuronsNum, 0.0 );
	m_backErrors.resize( _inputsNum, 0.0 );	

	for ( int i = 0; i < _neuronsNum; i++ )
	{
		if ( _isLast )
			m_neurons.push_back( new CNeuronLast( _inputsNum ) );
		else
			m_neurons.push_back( new CNeuron( _inputsNum ) );
	}
}


/*----------------------------------------------------------------------------*/


CLayer::CLayer( std::ifstream& _file, bool _isLast /*= false */ )
{
	_file.read( (char*)&m_inputsNum, sizeof( int ) );
	size_t neuronsSize;
	_file.read( (char*)&neuronsSize, sizeof( size_t ) );

	m_resultValues.resize( neuronsSize, 0.0 );
	m_backErrors.resize( m_inputsNum, 0.0 );

	for ( size_t i = 0; i < neuronsSize; i++ )
	{
		if ( _isLast )
			m_neurons.push_back( new CNeuronLast( _file ) );
		else
			m_neurons.push_back( new CNeuron( _file ) );
	}
}


/*----------------------------------------------------------------------------*/


CLayer::~CLayer()
{
	for ( size_t i = 0; i < m_neurons.size(); i++ )
	{
		if ( m_neurons[i] )
			delete m_neurons[i];
	}
}


/*----------------------------------------------------------------------------*/


void CLayer::CalcLocalErrors( const DoubleV& _data )
{
	for( size_t i = 0; i < m_neurons.size(); i++ )
	{
		m_neurons[i]->CalcLocalError( _data[i] );
	}
	// calculating backward errors
	CalcBackErrors();
}


/*----------------------------------------------------------------------------*/


int CLayer::GetNeuronsNum()
{
	return m_neurons.size();
}


/*----------------------------------------------------------------------------*/


void CLayer::CalculateOutputValues( const DoubleV& _inputValues )
{	
	for( size_t i = 0; i < m_neurons.size(); i++ )
	{		
		m_resultValues[i] = m_neurons[i]->CalculateOutputValue( _inputValues );		
	}
}


/*----------------------------------------------------------------------------*/


const DoubleV& CLayer::GetResultValues() const
{
	return m_resultValues;
}


/*----------------------------------------------------------------------------*/


const DoubleV& CLayer::GetBackErrors() const
{
	return m_backErrors;
}


/*----------------------------------------------------------------------------*/


void CLayer::CalcNewWeights( double _speed, const DoubleV& _inputValues )
{	
	for( size_t i = 0; i < m_neurons.size(); i++ )
	{
		m_neurons[i]->CalcNewWeights( _speed, _inputValues );
	}
}


/*----------------------------------------------------------------------------*/


void CLayer::CalcBackErrors()
{
	for( int i = 0; i < m_inputsNum; i++ )
	{
		m_backErrors[i] = 0.0;
		for( size_t j = 0; j < m_neurons.size(); j++ )
		{
			m_backErrors[i] += m_neurons[j]->GetWeightedError( i + 1 );
		}		
	}
}


/*----------------------------------------------------------------------------*/


void CLayer::PrintNeuroWeights()
{	
	for( size_t i = 0; i < m_neurons.size(); i++ )
	{
		printf("\n>\t Neuron %d:", i);
		m_neurons[i]->PrintWeights();
	}
}


/*----------------------------------------------------------------------------*/


void CLayer::PrintNeuroOutputs()
{	
	for( size_t i = 0; i < m_neurons.size(); i++ )
	{		
		printf("\n>\t Neuron %d: y = %f", i, m_resultValues[i]);		
	}
}


/*----------------------------------------------------------------------------*/


void CLayer::PrintError()
{
	for( size_t i = 0; i < m_neurons.size(); i++ )
	{		
		printf("\n>\t Neuron %d:", i);
		m_neurons[i]->PrintError();
	}	
}


/*----------------------------------------------------------------------------*/


void CLayer::PrintWeError()
{
	for( size_t i = 0; i < m_neurons.size(); i++ )
	{
		printf("\n>\t Neuron %d:", i);
		m_neurons[i]->PrintWeError();
	}
}


/*----------------------------------------------------------------------------*/


void CLayer::PrintBackError()
{
	for( int i = 0; i < m_inputsNum; i++ )
	{
		printf("\n>\t Prev.neuron %d: %f", i, m_backErrors[i] );
	}
}


/*----------------------------------------------------------------------------*/


void CLayer::SaveToFile( std::ofstream& _file )
{
	size_t neuronsSize = m_neurons.size(); 
	_file.write( (char*)&m_inputsNum, sizeof( int ) );
	_file.write( (char*)&neuronsSize, sizeof( size_t ) );	
	for( size_t i = 0; i < neuronsSize; i++ )
	{
		m_neurons[i]->SaveToFile( _file );
	}
}

/*----------------------------------------------------------------------------*/
